//==================================================================
//  Copyright (C) 2006  Davide Pasca
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//==================================================================
///
///
///
///
///
//==================================================================

#ifndef M5D_MESH_H
#define M5D_MESH_H

#include "m5d_model.h"
#include "m5d_mesh_geometry.h"
#include "m5d_tvert.h"

//==================================================================
struct VertexEdgeInfo;

//==================================================================
namespace M5D {

//==================================================================
class Mesh : public Model
{
	bool					_is_own_geom;
	u_int					_intflags;		// private use
	//Scene					*_scenep;

public:
	MeshGeometry			*_geomp;

private:
	Mesh( Scene *scenep, const char *namep = NULL, Mesh *copy_fromp = NULL, CopyParams *copy_paramsp = NULL );

	void	SetGeometry( MeshGeometry *geomp );
	void	CreateGeometry();

public:
	~Mesh();

	//==================================================================
	bool	IsOwnedGeometry() const
	{
		return _is_own_geom;
	}

	//==================================================================
	DispList	*OpenDispListIndex( PackVert::Type packvert_type=PackVert::TYPE_ANY, u_int max_verts=0, u_int max_prim_indices=0 )
	{
		return _geomp->OpenDispListIndex( _mod_scenep, packvert_type, max_verts, max_prim_indices );
	}
	DispList	*OpenDispListVertex( PackVert::Type packvert_type=PackVert::TYPE_ANY, u_int max_verts=0 )
	{
		return _geomp->OpenDispListVertex( _mod_scenep, packvert_type, max_verts );
	}
	void		CloseDispListIndex()	{ _geomp->CloseDispListIndex(); }
	void		CloseDispListVertex()	{ _geomp->CloseDispListVertex(); }


	const DispList	*GetDispListVertex() const	{	return _geomp->_displist_vtxp;	}
	const DispList	*GetDispListIndex()	const	{	return _geomp->_displist_idxp;	}

	//==================================================================
	u_short		*BeginAddIndexPrims( Material *matep, Primitive::Type prim_type, int n_prim_indices=0 )
	{
		return _geomp->_displist_idxp->BeginAddIndexPrims( matep, prim_type, n_prim_indices );
	}
	void		EndAddIndexPrims()
	{
		return _geomp->_displist_idxp->EndAddIndexPrims();
	}

	MultiVerts			&GetVerts()			{ return _geomp->GetVerts(); }
	const MultiVerts	&GetVerts()	const	{ return _geomp->GetVerts(); }
	Triangles			&GetTrigs()			{ return _geomp->GetTrigs(); }
	const Triangles		&GetTrigs() const	{ return _geomp->GetTrigs(); }

/*
	u_int	GetNLods() const
	{
		return _n_lods;
	}

	MultiVerts	*GetMeshVerts( int lod_idx ) const
	{
		return &_lods[lod_idx]._verts;
	}
*/
	//==================================================================
	virtual const PMath::Vector3	*GetBBoxMinPtr() const	{ return &_geomp->_box_min; }
	virtual const PMath::Vector3	*GetBBoxMaxPtr() const	{ return &_geomp->_box_max; }


	PMath::Vector3				&GetBBoxMin()		{ return _geomp->_box_min; }
	const PMath::Vector3		&GetBBoxMin() const	{ return _geomp->_box_min; }
	PMath::Vector3				&GetBBoxMax()		{ return _geomp->_box_max; }
	const PMath::Vector3		&GetBBoxMax() const	{ return _geomp->_box_max; }

	void				UpdateGeometry();

	Triangle			*AddTrigs( int add_n );
	Triangle			*AddTrigsDirty( int add_n );

	Triangle			&GetTriangle( u_int tidx )			{	return GetTrigs()._list[tidx];	}
	const Triangle		&GetTriangle( u_int tidx )	const	{	return GetTrigs()._list[tidx];	}
	Triangle			*msh_trig_addcopy( const Triangle *src_trip );

	void				TransformGeometry( const PMath::Matrix44 &trmat, const PMath::Matrix44 *normal_mp );
	void				ScaleAnim( float sx, float sy, float sz );
	bool				HasGeometry() const
	{
		return _geomp->GetVerts().GetPosN() > 0;
	}


	//--------------------------------------------------------------
	// _split.cpp
	void				msh_split_submeshes( int max_verts_per_mesh ) throw(...);
	Mesh				*move_mesh_geom( std::vector<int> &tri_list, int name_cnt );

	//--------------------------------------------------------------
	// _ext.cpp
	void				calcTrigsNormals();
	void				calcVertsNormals( bool smooth )	throw(...);
	void				CalcBoundingBox();
	void				UnshareVertsByNormalAngle( float base_hard_angle ) throw(...);

	void				UpdateIdxDispList() throw(...)	{	_geomp->UpdateIdxDispList( _mod_scenep );	}
	void				UpdateVtxDispList() throw(...)	{	_geomp->UpdateVtxDispList( _mod_scenep );	}

//private:
	void				killUnusedPosVerts() throw(...);
	void				eliminateUnusedVerts( VType::VType type_idx )	throw(...);
	void				eliminateBadTrigs( u_int range_begin=0, u_int range_end=0 );
	void				remapMaterials( const int *mat_idx_trans_tablep );
	void				remapVertsInTriangles( VType::VType type_idx, const std::vector<int> &idx_trans_table );
	void				OptimizeVerts( VType::VType type_idx ) throw(...);

	void				msh_weld( VType::VType type_idx, float tollerance, int from_vert_idx=0 ) throw(...);
	int					weld_do_weld_pos( int start_idx, int nv, std::vector<int> &idx_trans_table, float tollerance );
	int					weld_do_weld_tex( int start_idx, int nv, std::vector<int> &idx_trans_table, float tollerance );
	int					weld_do_weld_col( int start_idx, int nv, std::vector<int> &idx_trans_table, float tollerance );
	int					weld_do_weld_nor( int start_idx, int nv, std::vector<int> &idx_trans_table, float tollerance );

	void				CleanupGeometry();
	void				SimplifyGeometry( float out_triangle_count_ratio ) throw(...);

	//--------------------------------------------------------------
	void				markDispListUsedMaterials( DispList *displistp, u_int mark_flags );
	void				markTrigsUsedMaterials( u_int mark_flags );
	void				markMaterials( u_int flags );

private:
	void		DoSimplify( TriIdx_VertIdx &tidx_vidx,
							VertexEdgeInfo *vworkp,
							float out_tri_ratio );

	friend class	Model;
	friend class	Scene;
};
typedef autodel<Mesh>	Mesh_SP;

//==================================================================

};

#endif